﻿// ------------------------------------------------------------------------------
// <copyright file="AppBarButton.cs" company="skumaronline.com">
//    Copyright (C) 2012 Suresh Kumar T.
//
//    This program is free software; you can redistribute it and/or
//    modify it under the terms of the GNU General Public License
//    as published by the Free Software Foundation version 2
//    of the License.
//
//    This program is distributed in the hope that it will be useful,
//    but WITHOUT ANY WARRANTY; without even the implied warranty of
//    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
//    GNU General Public License for more details.
//
//    http://www.gnu.org/licenses/gpl-2.0.html
//
// </copyright>
// ------------------------------------------------------------------------------

namespace StoreAppLib.Controls
{
    using System;
    using System.Windows.Input;
    using Windows.UI.Core;
    using Windows.UI.Xaml;
    using Windows.UI.Xaml.Automation;
    using Windows.UI.Xaml.Controls;
    using Windows.UI.Xaml.Input;

    /// <summary>
    /// An AppBar button with in-inbuilt popup menu
    /// </summary>
    public sealed class AppBarButton : Button
    {
        /// <summary>
        /// Menu dependency property
        /// </summary>
        public static readonly DependencyProperty MenuProperty =
            DependencyProperty.Register("Menu", typeof(Menu), typeof(AppBarButton), new PropertyMetadata(null));

        /// <summary>
        /// Caption value dependency property
        /// </summary>
        public static readonly DependencyProperty CaptionProperty =
            DependencyProperty.Register("Caption", typeof(string), typeof(AppBarButton), new PropertyMetadata(string.Empty, OnCaptionPropertyChanged));

        /// <summary>
        /// Using a DependencyProperty as the backing store for menu command.  This enables animation, styling, binding, etc...
        /// </summary>
        public static readonly DependencyProperty MenuCommandProperty =
            DependencyProperty.Register("MenuCommand", typeof(ICommand), typeof(AppBarButton), new PropertyMetadata(null));
        
        /// <summary>
        /// Initializes a new instance of the <see cref="AppBarButton" /> class.
        /// </summary>
        public AppBarButton()
        {
            this.DefaultStyleKey = typeof(AppBarButton);

            this.Menu = new Menu();
        }

        /// <summary>
        /// Holds the handler for the event that is fired when the user invokes menu items
        /// </summary>
        public event MenuItemInvokedEventHandler MenuItemInvoked;

        /// <summary>
        /// Gets or sets Caption property.
        /// </summary>
        /// <value>
        /// The text.
        /// </value>
        public string Caption
        {
            get
            {
                return (string)this.GetValue(CaptionProperty);
            }

            set
            {
                this.SetValue(CaptionProperty, value);
            }
        }

        /// <summary>
        /// Gets or sets the menu
        /// </summary>
        public Menu Menu
        {
            get
            {
                return (Menu)this.GetValue(MenuProperty);
            }

            set
            {
                this.SetValue(MenuProperty, value);
            }
        }

        /// <summary>
        /// Gets or sets the menu command.
        /// </summary>
        /// <value>
        /// The menu command.
        /// </value>
        public ICommand MenuCommand
        {
            get
            {
                return (ICommand)this.GetValue(MenuCommandProperty);
            }

            set
            {
                this.SetValue(MenuCommandProperty, value);
            }
        }

        /// <summary>
        /// When tapped on this button, show menu.
        /// </summary>
        /// <param name="e">Tapped event argument</param>
        protected override void OnTapped(TappedRoutedEventArgs e)
        {
            if (this.Menu.Items.Count > 0)
            {
                e.Handled = true;

                this.Menu.MenuItemInvoked += this.OnMenuItemInvoked;

                this.Menu.Show(this, PopupAlignment.Top);
            }

            base.OnTapped(e);
        }

        /// <summary>
        /// Call back for Caption value change
        /// </summary>
        /// <param name="target">The target</param>
        /// <param name="args">Property changed call back event argument</param>
        private static void OnCaptionPropertyChanged(DependencyObject target, DependencyPropertyChangedEventArgs args)
        {
            AppBarButton button = target as AppBarButton;

            if (button != null && args.NewValue != args.OldValue)
            {
                button.UpdateText();
            }
        }

        /// <summary>
        /// Fire menu item invoked event when user invokes menu item
        /// </summary>
        /// <param name="sender">The app bar button</param>
        /// <param name="menuItem">The menu item</param>
        private async void OnMenuItemInvoked(object sender, MenuItem menuItem)
        {
            this.Menu.MenuItemInvoked -= this.OnMenuItemInvoked;

            MenuItemInvokedEventHandler menuItemInvoked = this.MenuItemInvoked;

            if (menuItemInvoked != null)
            {
                await this.Dispatcher.RunAsync(
                    CoreDispatcherPriority.Normal,
                    () =>
                    {
                        menuItemInvoked(this, menuItem);
                    });                
            }

            if (this.MenuCommand != null)
            {
                await this.Dispatcher.RunAsync(
                    CoreDispatcherPriority.Normal,
                    () =>
                    {
                        this.MenuCommand.Execute(menuItem);
                    });                
            }

            FrameworkElement control = this.Parent as FrameworkElement;

            while (control != null && !(control is AppBar))
            {
                control = control.Parent as FrameworkElement;
            }

            if (control != null && control is AppBar)
            {
                await this.Dispatcher.RunAsync(
                CoreDispatcherPriority.Normal,
                () =>
                {
                    (control as AppBar).IsOpen = false;
                });
            }
        }

        /// <summary>
        /// Update button caption
        /// </summary>
        private void UpdateText()
        {
            this.SetValue(AutomationProperties.NameProperty, this.Caption);
        }
    }
}
